using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using ZeroSum.DependencyInjection.Attributes;
using ZeroSum.DependencyInjection.Interfaces;
using ZeroSum.Extensions;

namespace ZeroSum.App.Filters;

/// <summary>
///     框架启动类，自动注册中间件
/// </summary>
public class StartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return app =>
        {
            // 扫描所有Startup并进行中间件注册
            UseStartups(app);
            next(app);
        };
    }

    /// <summary>
    ///     从所有程序集中过滤出实现了IAppStartup的启动类，进行实例化并执行中间件注册
    /// </summary>
    /// <param name="app"></param>
    private void UseStartups(IApplicationBuilder app)
    {
        var assemblies = InternalApp.Assemblies;
        var target = typeof(IAppStartup);
        var types = assemblies.SelectMany(x => x.GetTypes().Where(t => t.IsPublic));

        // 查找所有实现了IAppStartup接口的普通类
        var startups = types.Where(x => target.IsAssignableFrom(x) && x.IsClass && !x.IsAbstract && !x.IsGenericType)
            .OrderByDescending(GetOrder);

        // 顺序执行Configuration
        foreach (var type in startups)
        {
            var startup = Activator.CreateInstance(type) as IAppStartup;
            startup?.Configuration(app);
        }
    }

    /// <summary>
    ///     对注册项进行排序
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private static int GetOrder(Type type)
    {
        return type.HasAttribute<StartupOrder>() ? type.GetAttribute<StartupOrder>()!.Order : 0;
    }
}